#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

#include <wand/magick_wand.h>

#include <http_func.h>
#include <fdfs_http_shared.h>

#define HTTPD_MAX_PARAMS   32

typedef struct {
    size_t max_size;
    ngx_str_t image_type;
    ngx_flag_t gif_enable;
    ngx_uint_t tracker_num;
    ngx_flag_t enable;
} ngx_http_fastdfs_gm_loc_conf_t;

static ngx_int_t ngx_http_fastdfs_gm_handler(ngx_http_request_t *r);

static void *ngx_http_fastdfs_gm_create_loc_conf(ngx_conf_t *cf) {
    ngx_http_fastdfs_gm_loc_conf_t *conf = ngx_pcalloc(cf->pool, sizeof (ngx_http_fastdfs_gm_loc_conf_t));
    if (conf == NULL) {
        return NGX_CONF_ERROR;
    }

    conf->max_size = NGX_CONF_UNSET_SIZE;
    conf->image_type.len = 0;
    conf->image_type.data = NULL;
    conf->gif_enable = NGX_CONF_UNSET;
    conf->tracker_num = NGX_CONF_UNSET_UINT;
    conf->enable = NGX_CONF_UNSET;

    return conf;
}

static char *ngx_http_fastdfs_gm_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) {
    ngx_http_fastdfs_gm_loc_conf_t *prev = parent;
    ngx_http_fastdfs_gm_loc_conf_t *conf = child;

    ngx_conf_merge_size_value(conf->max_size, prev->max_size, 1024);
    ngx_conf_merge_str_value(conf->image_type, prev->image_type, "jpg");
    ngx_conf_merge_value(conf->gif_enable, prev->gif_enable, 0);
    ngx_conf_merge_uint_value(conf->tracker_num, prev->tracker_num, 1);
    ngx_conf_merge_value(conf->enable, prev->enable, 0);

    return NGX_CONF_OK;
}

static ngx_http_module_t ngx_http_fastdfs_gm_module_ctx = {
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    ngx_http_fastdfs_gm_create_loc_conf,
    ngx_http_fastdfs_gm_merge_loc_conf
};

static char *ngx_http_fastdfs_gm_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
    ngx_http_core_loc_conf_t *clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_fastdfs_gm_handler;
    return NGX_CONF_OK;
}

static ngx_command_t ngx_http_fastdfs_gm_module_commands[] = {
    {
        ngx_string("ngx_fastdfs_gm_module"),
        NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS,
        ngx_http_fastdfs_gm_set,
        NGX_HTTP_LOC_CONF_OFFSET,
        0,
        NULL
    },
    {
        ngx_string("max_size"),
        NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
        ngx_conf_set_size_slot,
        NGX_HTTP_LOC_CONF_OFFSET,
        offsetof(ngx_http_fastdfs_gm_loc_conf_t, max_size),
        NULL
    },
    {
        ngx_string("image_type"),
        NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
        ngx_conf_set_str_slot,
        NGX_HTTP_LOC_CONF_OFFSET,
        offsetof(ngx_http_fastdfs_gm_loc_conf_t, image_type),
        NULL
    },
    {
        ngx_string("gif_enable"),
        NGX_HTTP_LOC_CONF | NGX_CONF_FLAG,
        ngx_conf_set_flag_slot,
        NGX_HTTP_LOC_CONF_OFFSET,
        offsetof(ngx_http_fastdfs_gm_loc_conf_t, gif_enable),
        NULL
    },
    {
        ngx_string("tracker_num"),
        NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
        ngx_conf_set_num_slot,
        NGX_HTTP_LOC_CONF_OFFSET,
        offsetof(ngx_http_fastdfs_gm_loc_conf_t, tracker_num),
        NULL
    },
    ngx_null_command
};

static ngx_int_t ngx_http_fastdfs_gm_process_init(ngx_cycle_t *cycle) {
    InitializeMagick(NULL);
    //ExceptionInfo exception;
    //GetExceptionInfo(&exception);
    //image = BlobToImage(image_info, binary_data, count, &exception);
    //fprintf(stderr, "exception: %s %s\n", exception.module, exception.reason);
    return NGX_OK;
}

static void ngx_http_fastdfs_gm_process_exit(ngx_cycle_t *cycle) {
    DestroyMagick();
}

ngx_module_t ngx_http_fastdfs_gm_module = {
    NGX_MODULE_V1,
    &ngx_http_fastdfs_gm_module_ctx,
    ngx_http_fastdfs_gm_module_commands,
    NGX_HTTP_MODULE,
    NULL,
    NULL,
    ngx_http_fastdfs_gm_process_init,
    NULL,
    NULL,
    ngx_http_fastdfs_gm_process_exit,
    NULL,
    NGX_MODULE_V1_PADDING
};

static unsigned char *get_transition_image(const char *full_filename, size_t *len, char *image_params) {
    MagickWand *wand = NULL, *new_wand = NULL;
    unsigned char *blob_data = NULL;

    if (full_filename == NULL) {
        return NULL;
    }
    if (image_params == NULL || *image_params == '\0') {
        return NULL;
    }

    wand = NewMagickWand();
    new_wand = NewMagickWand();

    if (MagickReadImage(wand, full_filename) == MagickFalse) {
        return NULL;
    }

    new_wand = MagickTransformImage(wand, image_params, "");
    MagickSetCompressionQuality(wand, 95);
    blob_data = MagickWriteImageBlob(new_wand, len);

    wand = DestroyMagickWand(wand);
    new_wand = DestroyMagickWand(new_wand);

    return blob_data;
}

static ngx_int_t ngx_http_fastdfs_gm_handler(ngx_http_request_t *r) {
    ngx_int_t rc;
    ngx_buf_t *b;
    ngx_chain_t out;

    ngx_http_fastdfs_gm_loc_conf_t *cglcf = ngx_http_get_module_loc_conf(r, ngx_http_fastdfs_gm_module);

    printf("max_size:%d\n", cglcf->max_size);
    printf("image_type:%s\n", cglcf->image_type.data);
    printf("gif_enable:%d\n", cglcf->gif_enable);
    printf("tracker_num:%d\n", cglcf->tracker_num);

    if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    /***** 获取资源 start ********/
    char uri[512];
    char *p;

    p = uri;
    if (r->uri.len > 0) {
        memcpy(p, r->uri.data, r->uri.len);
        p += r->uri.len;
    }
    *p = '\0';
    printf("uri:%s\n", uri);
    /***** 获取资源 end ********/

    //char full_filename[MAX_PATH_SIZE + 64];
    //int full_filename_len;
    //full_filename_len = snprintf(full_filename, sizeof(full_filename), "%s/data/%s", g_fdfs_store_paths[store_path_index], true_filename);

    /***** 获取url参数 start ********/
    int param_count;
    KeyValuePair params[HTTPD_MAX_PARAMS];

    char args[256];

    if (r->args.len + 1 >= sizeof (args)) {
        return NGX_HTTP_BAD_REQUEST;
    }

    p = args;
    if (r->args.len > 0) {
        *p++ = '?';
        memcpy(p, r->args.data, r->args.len);
        p += r->args.len;
    }
    *p = '\0';
    printf("args:%s\n", args);
    param_count = http_parse_query(args, params, HTTPD_MAX_PARAMS);
    printf("param_count:%d\n", param_count);
    int i;
    for (i = 0; i < param_count; i++) {
        printf("key-value:%s-%s\n", params[i].key, params[i].value);
    }
    /***** 获取url参数 end ********/

    size_t image_len;
    unsigned char *blob_data = get_transition_image("/usr/local/application/fastdfs-3.09/store_path0/data/00/00/wKgjvE_77bLsM_6XACnT6RonchI312.jpg", &image_len, "250x250+0+0");

    ngx_str_t sh = ngx_string("ddd");

    if (r->headers_in.if_modified_since) {
        return NGX_HTTP_NOT_MODIFIED;
    }

    r->headers_out.content_type.len = sizeof ("image/jpg") - 1; //image/jpg//text/html
    r->headers_out.content_type.data = (u_char *) "image/jpg";
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = image_len;

    if (r->method == NGX_HTTP_HEAD) {
        rc = ngx_http_send_header(r);
        if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
            return rc;
        }
    }

    b = ngx_pcalloc(r->pool, sizeof (ngx_buf_t));
    if (b == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    out.buf = b;
    out.next = NULL;

    b->pos = blob_data;
    b->last = blob_data + image_len;

    b->memory = 1;
    b->last_buf = 1;

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        return rc;
    }
    return ngx_http_output_filter(r, &out);
}